package com.lanyou.esb.cook.proxy.servlet;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Date;
import java.util.Enumeration;
import java.util.Formatter;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.AbortableHttpRequest;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicHttpEntityEnclosingRequest;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.message.HeaderGroup;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.util.EntityUtils;

import com.lanyou.esb.cook.proxy.auth.AuthInvocation;
import com.lanyou.esb.cook.proxy.common.Constants;
import com.lanyou.esb.cook.proxy.common.SystemResCode;
import com.lanyou.esb.cook.proxy.entity.AccLog;
import com.lanyou.esb.cook.proxy.entity.FieldSystem;
import com.lanyou.esb.cook.proxy.entity.Http;
import com.lanyou.esb.cook.proxy.entity.IfAccTimes;
import com.lanyou.esb.cook.proxy.entity.IfAlarm;
import com.lanyou.esb.cook.proxy.entity.IfAlrReqTimes;
import com.lanyou.esb.cook.proxy.entity.IfAvgResTimes;
import com.lanyou.esb.cook.proxy.entity.IfReqQuantity;
import com.lanyou.esb.cook.proxy.entity.PfThroughput;
import com.lanyou.esb.cook.proxy.entity.StoreForward;
import com.lanyou.esb.cook.proxy.entity.Token;
import com.lanyou.esb.cook.proxy.exception.AuthException;
import com.lanyou.esb.cook.proxy.exception.IfAlarmException;
import com.lanyou.esb.cook.proxy.meta.AlarmLevel;
import com.lanyou.esb.cook.proxy.meta.AlarmType;
import com.lanyou.esb.cook.proxy.meta.AuthType;
import com.lanyou.esb.cook.proxy.meta.EnableType;
import com.lanyou.esb.cook.proxy.meta.Environment;
import com.lanyou.esb.cook.proxy.meta.IfType;
import com.lanyou.esb.cook.proxy.meta.ReqResultType;
import com.lanyou.esb.cook.proxy.meta.StoreForwardStatus;
import com.lanyou.esb.cook.proxy.meta.SystemType;
import com.lanyou.esb.cook.proxy.meta.TimeUnit;
import com.lanyou.esb.cook.proxy.meta.TraceType;
import com.lanyou.esb.cook.proxy.service.ConcurrencyNumberService;
import com.lanyou.esb.cook.proxy.service.FieldSystemService;
import com.lanyou.esb.cook.proxy.service.HttpService;
import com.lanyou.esb.cook.proxy.service.IfAlarmService;
import com.lanyou.esb.cook.proxy.service.IfAlrReqTimesService;
import com.lanyou.esb.cook.proxy.service.IfReqQuantityService;
import com.lanyou.esb.cook.proxy.service.RedisBatchService;
import com.lanyou.esb.cook.proxy.service.StoreForwardService;
import com.lanyou.esb.cook.proxy.service.TraceLogService;
import com.lanyou.esb.cook.proxy.service.impl.ConcurrencyNumberServiceImpl;
import com.lanyou.esb.cook.proxy.service.impl.StoreForwardServiceImpl;
import com.lanyou.esb.cook.proxy.service.impl.TraceLogServiceImpl;
import com.lanyou.esb.cook.proxy.vo.EntityGroup;
import com.lanyou.esb.cook.proxy.vo.ErrorMsg;
import com.lanyou.esb.cook.proxy.vo.ResultMsg;

/**
 * HTTP请求代理
 * 
 * @author Davey.wu
 */
public class Proxy {
	/** 领域系统服务接口 */
	private FieldSystemService fieldSystemService;
	/** 领域系统服务接口 */
	private HttpService httpService;
	/** 接口请求量控制 **/
	private IfReqQuantityService ifReqQuantityService;
	/** 接口已请求次数服务 **/
	private IfAlrReqTimesService ifAlrReqTimesService;
	/** 权限验证调度器 **/
	private AuthInvocation authInvocation;
	/** 跟踪日志接口 **/
	private TraceLogService traceLogService;
	/** 接口告警信息 **/
	private IfAlarmService ifAlarmService;
	/** 请求转发统计表 **/
	private StoreForwardService storeForwardService;
	/** 并发数接口 **/
	private ConcurrencyNumberService concurrencyNumberService;

	private RedisBatchService redisBatchService;

	/** 请求头集合 **/
	protected static final HeaderGroup hopByHopHeaders;

	static {
		hopByHopHeaders = new HeaderGroup();
		String[] headers = new String[] { "Connection", "Keep-Alive",
				"Proxy-Authenticate", "Proxy-Authorization", "TE", "Trailers",
				"Transfer-Encoding", "Upgrade" };
		for (String header : headers) {
			hopByHopHeaders.addHeader(new BasicHeader(header, null));
		}
	}

	private static final BitSet asciiQueryChars;
	static {
		char[] c_unreserved = "_-!.~'()*".toCharArray();// plus alphanum
		char[] c_punct = ",;:$&+=".toCharArray();
		char[] c_reserved = "?/[]@".toCharArray();// plus punct

		asciiQueryChars = new BitSet(128);
		for (char c = 'a'; c <= 'z'; c++)
			asciiQueryChars.set((int) c);
		for (char c = 'A'; c <= 'Z'; c++)
			asciiQueryChars.set((int) c);
		for (char c = '0'; c <= '9'; c++)
			asciiQueryChars.set((int) c);
		for (char c : c_unreserved)
			asciiQueryChars.set((int) c);
		for (char c : c_punct)
			asciiQueryChars.set((int) c);
		for (char c : c_reserved)
			asciiQueryChars.set((int) c);

		asciiQueryChars.set((int) '%');
	}

	private String getIpAddress(HttpServletRequest request) {
		String ip = request.getHeader("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		}
		return ip;
	}

	/**
	 * 处理请求入口
	 * 
	 * @param request
	 *            ：请求对象
	 * @param response
	 *            ：响应对象
	 * @param servlet
	 *            ：SERVLET对象
	 * @param systemCode
	 *            ：系统编码
	 * @param ifCode
	 *            ：接口编码
	 * @param ifVersion
	 *            ：接口版本
	 * @param environment
	 *            ：运行环境
	 * @throws ServletException
	 * @throws IOException
	 */
	public void process(HttpServletRequest request,
			HttpServletResponse response, HttpServlet servlet,
			String systemCode, String ifCode, String ifVersion,
			Environment environment) throws ServletException, IOException {
		// 进入ESB时间
		Date inEsbDate = new Date();
		// 创建日志对象
		AccLog log = createLog();
		// 设置进入ESB时间
		log.setInEsbDate(inEsbDate);

		// 只在正式环境下才对数据进行统计，以下两步顺序不能变
		if (Environment.PRODUCTION == environment) {
			// 第一步，先增加请求数
			ConcurrencyNumberServiceImpl.incReqNumber();
			// 第二步，再将当前秒毫秒的补数存入REDIS，即为当前秒至下一秒之间的并发量要减去（1000-当前时间的毫秒数）
			concurrencyNumberService.pushToRedis(inEsbDate);
		}
		// 请求真实IP地址
		String reqIp = getIpAddress(request);
		// 设置请求IP
		log.setRequestId(reqIp);
		// 请求报文
		String content = "";
		// 告警列表
		List<IfAlarm> alarmList = new ArrayList<>(3);
		// HTTP接口
		Http http = null;
		// 令牌
		Token token = null;
		// 发布方系统
		FieldSystem system = null;
		// 调用方系统
		FieldSystem callSystem = null;
		// 状态
		int statusCode = 200;
		// 告警对象
		IfAlarm ifAlarm = null;
		// 接口请求量控制
		IfReqQuantity ifReqQuantity = null;
		// 接口已访问次数
		IfAlrReqTimes ifAlrReqTimes = null;
		// 实体组合
		EntityGroup entityGroup = null;
		ResultMsg resultMsg = new ResultMsg();
		try {
			// 获取发布方系统和接口信息
			entityGroup = redisBatchService.getPubSystemAndHttp(systemCode,
					ifCode, ifVersion);
			if (entityGroup != null) {
				system = entityGroup.getPubSystem();
			}
			// 找不到发布方系统
			if (system == null) {
				// 抛出异常
				throw new AuthException(SystemResCode.MSG_UNKNOW_SYSTEM,
						SystemResCode.CODE_UNKNOW_SYSTEM);
			}
			log.setFieldId(system.getFieldId());
			log.setSystemId(system.getId());
			// 校验系统可用性
			fieldSystemService.validate(system, SystemType.PROVIDER);
			// 查询此系统是否注册值为requestUri的接口,如果此接口未注册,则返回404错误
			http = entityGroup.getHttp();
			// 找不到调用方系统
			if (http == null) {
				// 抛出异常
				throw new AuthException(SystemResCode.MSG_UNKNOW_INTERFACE,
						SystemResCode.CODE_UNKNOW_INTERFACE);
			}

			// 设置是否开启跟踪日志
			if (Environment.PRODUCTION == environment
					&& TraceType.OPEN.ValueCode.equals(http.getIsTrace())) {
				TraceLogServiceImpl.openTrace();
				// 设置日志基本信息
				TraceLogServiceImpl.addBaseInfo(Constants.IF_ID_KEY,
						http.getId());
				TraceLogServiceImpl.addBaseInfo(Constants.CREATOR_KEY,
						http.getCreator());
			}
			// 记录接口表ID
			log.setIfId(http.getId());
			// 记录接口类型
			log.setIfType(http.getType());
			// 记录接口名称
			log.setIfName(http.getName());
			// 校验接口可用性
			httpService.validate(http);

			// 读取请求内容
			byte[] bytes = readContent(request);
			content = new String(bytes);
			// 获取验证信息
			Map<String, Object> authInfo = authInvocation.getAuthInfo(request,
					content, http, environment);
			// 设置日志基本信息
			TraceLogServiceImpl.addBaseInfo(Constants.CALLSYSTEMCODE_KEY,
					authInfo.get(Constants.CALL_SYSTEM_CODE));

			// 获取令牌，调用方系统，接口请求量控制，接口已访问次数start===============================
			// 默认取正式的令牌
			Environment tempEnv = Environment.PRODUCTION;
			// 如果是OAUTH认证类型，则取测试令牌
			if (AuthType.OAUTH.ValueCode.equals(http.getAuthType())
					&& Environment.TEST == environment) {
				tempEnv = Environment.TEST;
			}
			entityGroup = redisBatchService.batchGet(systemCode,
					(String) authInfo.get(Constants.CALL_SYSTEM_CODE), ifCode,
					http.getId(), ifVersion, TimeUnit.DAY, inEsbDate, tempEnv);
			if (entityGroup != null) {
				// 获取令牌
				token = entityGroup.getToken();
				// 获取调用方系统
				callSystem = entityGroup.getCallSystem();
				// 获取接口请求量控制
				ifReqQuantity = entityGroup.getIfReqQuantity();
				// 获取接口已访问次数
				ifAlrReqTimes = entityGroup.getIfAlrReqTimes();
			}
			// 获取令牌，调用方系统，接口请求量控制，接口已访问次数end===============================

			// 找不到调用方系统
			if (callSystem == null) {
				// 记录跟踪日志
				if (TraceLogServiceImpl.isTrace()) {
					TraceLogServiceImpl.addTraceLog(
							SystemResCode.MSG_UNKNOW_CALL_SYSTEM,
							Constants.FLAG_LEFT_SQUARE_BRACKET,
							Constants.CALL_SYSTEM_CODE, Constants.FLAG_EQUAL,
							authInfo.get(Constants.CALL_SYSTEM_CODE) + "",
							Constants.FLAG_RIGHT_SQUARE_BRACKET);
				}
				// 抛出异常
				throw new AuthException(SystemResCode.MSG_UNKNOW_CALL_SYSTEM,
						SystemResCode.CODE_UNKNOW_CALL_SYSTEM);
			}
			// 校验系统可用性
			fieldSystemService.validate(callSystem, SystemType.CONSUMER);
			// 将调用方系统编码加入权限验证消息映射集
			authInfo.put(Constants.CALL_SYSTEM_CODE, callSystem.getCode());
			// 将调用方系统ID加入权限验证消息映射集
			authInfo.put(Constants.CALL_SYSTEM_ID, callSystem.getId());

			log.setCallSystemId(callSystem.getId());
			log.setCreator(callSystem.getCreator());
			log.setModifier(callSystem.getCreator());

			// 如果此接口需要安全认证,则开始进行认证start===========================
			if (!AuthType.NOAUTH.ValueCode.equals(http.getAuthType())) {
				// 权限校验
				boolean authResult = authInvocation.auth(
						request.getLocalAddr(), system, http,
						(String) authInfo.get(Constants.CALL_SYSTEM_CODE),
						environment, authInfo, token);
				// 校验失败
				if (!authResult) {
					// 记录跟踪日志
					if (TraceLogServiceImpl.isTrace()) {
						TraceLogServiceImpl
								.addTraceLog(SystemResCode.MSG_AUTH_FAILURE);
					}
					// 抛出异常
					throw new AuthException(SystemResCode.MSG_AUTH_FAILURE,
							SystemResCode.CODE_AUTH_FAILURE);
				}
				// 记录跟踪日志
				if (TraceLogServiceImpl.isTrace()) {
					TraceLogServiceImpl.addTraceLog(Constants.MSG_AUTH_SUCCESS);
				}
			}
			// 如果此接口需要安全认证,则开始进行认证end===========================

			// 先判断请求量是否超标，start=========================
			if (Environment.PRODUCTION == environment && ifReqQuantity != null) {
				if (ifAlrReqTimes == null) {
					// 创建接口已请求次数
					ifAlrReqTimes = ifAlrReqTimesService.create(http.getId(),
							TimeUnit.DAY, callSystem.getCode(),
							log.getInEsbDate());
				}
				ifAlarm = alarm(ifReqQuantity, ifAlrReqTimes, inEsbDate);
				if (ifAlarm != null) {
					// 超过请求阀值,添加告警信息
					ifAlarm.setErrorReceiver(system.getCreator())
							.setSystemId(system.getId())
							.setSystemCode(system.getCode()).setIfCode(ifCode)
							.setIfVersion(ifVersion)
							.setCallSystemCode(callSystem.getCode())
							.setReqMess(content).setReqIp(reqIp)
							.setReqMethod(request.getMethod())
							.setReqUrl(request.getRequestURL().toString())
							.setResCode(statusCode + "")
							.setEmailReceiver(getEmailReceiver(token));
					alarmList.add(ifAlarm);
				}
			}
			// 判断请求量是否超标，end=========================

			// 转发请求，start=========================
			statusCode = doProxy(request, bytes, response, system, http, log,
					servlet, environment);
			// 转发请求，end=========================

			// HTTP-400异常
			if (statusCode >= 400 && statusCode < 500) {
				Date now = new Date();
				// 添加告警信息
				IfAlarm alarm = ifAlarmService.create(system, callSystem, http,
						request, AlarmType.HTTP_400.ValueCode,
						AlarmLevel.URGENT.ValueCode, 0, 0, reqIp, content,
						statusCode + "", getEmailReceiver(token), now, 0.0f,
						0.0f, now);
				alarmList.add(alarm);
			}
			// 记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				TraceLogServiceImpl.addTraceLog(Constants.MSG_REQ_END);
			}
			resultMsg.setResultCode(ReqResultType.SUCCEED.ValueCode);
			resultMsg.setResultDesc(Constants.MSG_REQ_SUCCESS);
		}
		// 验证异常
		catch (AuthException e) {
			// 设置结果为失败
			resultMsg.setResultCode(ReqResultType.FAILURE.ValueCode);
			resultMsg.setResultDesc(Constants.MSG_REQ_FAILURE);
			log.setReqResult(ReqResultType.FAILURE.ValueCode);

			ErrorMsg msg = ErrorMsg.getInstance(e.getCode(), e.getMessage());
			// 记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				TraceLogServiceImpl.addTraceLog(msg.toJson());
			}
			resultMsg.setError(msg);
			response.sendError(HttpServletResponse.SC_UNAUTHORIZED, URLEncoder
					.encode(msg.toJson(), Constants.ENCODING_TYPE_UTF8));
		} catch (IfAlarmException e) {
			Date now = new Date();
			// 出现告警，并且导致COOKPROXY不转发请求，设置平台请求及响应时间为当前时间
			log.setPlatReqDate(now);
			log.setPlatResDate(now);

			// 设置结果为失败
			resultMsg.setResultCode(ReqResultType.FAILURE.ValueCode);
			resultMsg.setResultDesc(Constants.MSG_REQ_FAILURE);
			log.setReqResult(ReqResultType.FAILURE.ValueCode);

			// 添加告警信息
			IfAlarm alarm = ifAlarmService.create(system, callSystem, http,
					request, e.getType().ValueCode, e.getLevel().ValueCode,
					e.getFlow(), e.getFlowThreshold(), reqIp, content,
					statusCode + "", getEmailReceiver(token), now, 0.0f, 0.0f,
					now);
			alarmList.add(alarm);

			StringBuilder resultDesc = new StringBuilder();
			resultDesc.append(e.getMessage()).append(Constants.FLAG_DOT_SYMBOL)
					.append(Constants.MSG_ALARM_TYPE)
					.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
					.append(e.getType().ValueCode)
					.append(Constants.FLAG_RIGHT_SQUARE_BRACKET)
					.append(Constants.FLAG_SEMICOLON)
					.append(Constants.MSG_ALARM_LEVEL)
					.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
					.append(e.getLevel().ValueCode)
					.append(Constants.FLAG_RIGHT_SQUARE_BRACKET);
			ErrorMsg msg = ErrorMsg.getInstance(e.getCode(),
					resultDesc.toString());
			// 记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				TraceLogServiceImpl.addTraceLog(msg.toJson());
			}
			resultMsg.setError(msg);
			response.sendError(HttpServletResponse.SC_UNAUTHORIZED, URLEncoder
					.encode(msg.toJson(), Constants.ENCODING_TYPE_UTF8));
		}
		// 请求超时异常，添加请求超时告警
		catch (ConnectTimeoutException e) {
			// 设置结果为失败
			resultMsg.setResultCode(ReqResultType.FAILURE.ValueCode);
			resultMsg.setResultDesc(Constants.MSG_REQ_FAILURE);
			log.setReqResult(ReqResultType.FAILURE.ValueCode);

			Date now = new Date();
			// 请求超时，添加告警信息
			IfAlarm alarm = ifAlarmService.create(system, callSystem, http,
					request, AlarmType.REQUEST_TIMEOUT.ValueCode,
					AlarmLevel.URGENT.ValueCode, 0, 0, reqIp, content,
					statusCode + "", getEmailReceiver(token), now,
					log.getPlatTimes(), http.getOvertimeTimes() / 1000.0f, now);
			alarmList.add(alarm);

			StringBuilder resultDesc = new StringBuilder();
			resultDesc
					.append(SystemResCode.MSG_REQUEST_TIMEOUT)
					.append(Constants.FLAG_DOT_SYMBOL
							+ Constants.MSG_ALARM_TYPE)
					.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
					.append(AlarmType.REQUEST_TIMEOUT.ValueCode)
					.append(Constants.FLAG_RIGHT_SQUARE_BRACKET)
					.append(Constants.FLAG_SEMICOLON
							+ Constants.MSG_ALARM_LEVEL)
					.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
					.append(AlarmLevel.URGENT.ValueCode)
					.append(Constants.FLAG_RIGHT_SQUARE_BRACKET);
			ErrorMsg msg = ErrorMsg.getInstance(
					SystemResCode.CODE_REQUEST_TIMEOUT, resultDesc.toString());
			// 记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				TraceLogServiceImpl.addTraceLog(msg.toJson());
			}

			resultMsg.setError(msg);
			response.sendError(HttpServletResponse.SC_BAD_REQUEST, URLEncoder
					.encode(msg.toJson(), Constants.ENCODING_TYPE_UTF8));
		}
		// 连接不到远程主机异常，添加HTTP-400告警
		catch (HttpHostConnectException e) {
			// 设置结果为失败
			resultMsg.setResultCode(ReqResultType.FAILURE.ValueCode);
			resultMsg.setResultDesc(Constants.MSG_REQ_FAILURE);
			log.setReqResult(ReqResultType.FAILURE.ValueCode);

			Date now = new Date();
			// 连接不到远程主机，添加告警信息
			IfAlarm alarm = ifAlarmService.create(system, callSystem, http,
					request, AlarmType.HTTP_400.ValueCode,
					AlarmLevel.URGENT.ValueCode, 0, 0, reqIp, content, "400",
					getEmailReceiver(token), now, 0.0f, 0.0f, now);
			alarmList.add(alarm);

			StringBuilder resultDesc = new StringBuilder();
			resultDesc
					.append(SystemResCode.MSG_HTTP_HOST_CONN_EXCE)
					.append(Constants.FLAG_DOT_SYMBOL
							+ Constants.MSG_ALARM_TYPE)
					.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
					.append(AlarmType.HTTP_400.ValueCode)
					.append(Constants.FLAG_RIGHT_SQUARE_BRACKET)
					.append(Constants.FLAG_SEMICOLON
							+ Constants.MSG_ALARM_LEVEL)
					.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
					.append(AlarmLevel.URGENT.ValueCode)
					.append(Constants.FLAG_RIGHT_SQUARE_BRACKET);
			ErrorMsg msg = ErrorMsg.getInstance(
					SystemResCode.CODE_HTTP_HOST_CONN_EXCE,
					resultDesc.toString());
			// 记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				TraceLogServiceImpl.addTraceLog(msg.toJson());
			}
			resultMsg.setError(msg);
			response.sendError(HttpServletResponse.SC_NOT_FOUND, URLEncoder
					.encode(msg.toJson(), Constants.ENCODING_TYPE_UTF8));

		}
		// 连接夽接字异常异常，添加HTTP-400告警
		catch (SocketException e) {
			// 设置结果为失败
			resultMsg.setResultCode(ReqResultType.FAILURE.ValueCode);
			resultMsg.setResultDesc(Constants.MSG_REQ_FAILURE);
			log.setReqResult(ReqResultType.FAILURE.ValueCode);

			Date now = new Date();
			// 连接不到远程主机，添加告警信息
			IfAlarm alarm = ifAlarmService.create(system, callSystem, http,
					request, AlarmType.HTTP_400.ValueCode,
					AlarmLevel.URGENT.ValueCode, 0, 0, reqIp, content, "400",
					getEmailReceiver(token), now, 0.0f, 0.0f, now);
			alarmList.add(alarm);

			StringBuilder resultDesc = new StringBuilder();
			resultDesc
					.append(SystemResCode.MSG_SOCKET_EXCE)
					.append(Constants.FLAG_DOT_SYMBOL
							+ Constants.MSG_ALARM_TYPE)
					.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
					.append(AlarmType.HTTP_400.ValueCode)
					.append(Constants.FLAG_RIGHT_SQUARE_BRACKET)
					.append(Constants.FLAG_SEMICOLON
							+ Constants.MSG_ALARM_LEVEL)
					.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
					.append(AlarmLevel.URGENT.ValueCode)
					.append(Constants.FLAG_RIGHT_SQUARE_BRACKET);
			ErrorMsg msg = ErrorMsg.getInstance(SystemResCode.CODE_SOCKET_EXCE,
					resultDesc.toString());
			// 记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				TraceLogServiceImpl.addTraceLog(msg.toJson());
			}
			resultMsg.setError(msg);
			response.sendError(HttpServletResponse.SC_NOT_FOUND, URLEncoder
					.encode(msg.toJson(), Constants.ENCODING_TYPE_UTF8));

		}
		// 未知异常
		catch (Exception e) {
			// 设置结果为失败
			resultMsg.setResultCode(ReqResultType.FAILURE.ValueCode);
			resultMsg.setResultDesc(Constants.MSG_REQ_FAILURE);
			log.setReqResult(ReqResultType.FAILURE.ValueCode);

			StringBuilder resultDesc = new StringBuilder();
			resultDesc
					.append(SystemResCode.MSG_OTHER_EXCEPTION)
					.append(Constants.FLAG_COMMA_SYMBOL
							+ Constants.MSG_DETIAL_INFO)
					.append(Constants.FLAG_COLON
							+ Constants.FLAG_LEFT_SQUARE_BRACKET
							+ e.getClass().getName() + Constants.FLAG_COLON
							+ e.getMessage()
							+ Constants.FLAG_RIGHT_SQUARE_BRACKET);
			ErrorMsg msg = ErrorMsg.getInstance(
					SystemResCode.CODE_OTHER_EXCEPTION, resultDesc.toString());
			// 记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				TraceLogServiceImpl.addTraceLog(msg.toJson());
			}
			resultMsg.setError(msg);
			response.sendError(HttpServletResponse.SC_BAD_REQUEST, URLEncoder
					.encode(msg.toJson(), Constants.ENCODING_TYPE_UTF8));
		} finally {
			// 测试环境，不记录调用信息，也不作数据统计
			if (Environment.TEST == environment) {
				return;
			}
			log.setReqResultDesc(resultMsg.toJson());
			Date outEsbDate = new Date();
			try {
				log.setOutEsbDate(outEsbDate);
				log.setLastUpdatedDate(outEsbDate);

				// 没有发布方系统，或者没有接口，或者没有调用方系统，不会进入接口调用流程，也就没有接口调用记录，直接返回
				if (system == null || callSystem == null || http == null) {
					return;
				}

				// 记录接口平均响应时间 start===============================
				IfAvgResTimes ifAvgResTimes = new IfAvgResTimes()
						.setIfId(log.getIfId())
						.setStartDate(log.getOutEsbDate())
						.setAvgResTimes(log.getTotalResTimes());
				// 记录接口平均响应时间 end===============================

				// 记录平台吞吐量start===============================
				PfThroughput pfThroughput = new PfThroughput()
						.setFieldId(log.getFieldId())
						.setStatisticsDate(log.getOutEsbDate())
						.setThroughputQty(log.getThroughputQty())
						.setIsEnable(log.getIsEnable())
						.setCreator(log.getCreator())
						.setCreateDate(log.getCreatedDate())
						.setModifier(log.getModifier())
						.setLastUpdatedDate(log.getLastUpdatedDate());
				// 记录平台吞吐量end===============================

				// 记录接口访问次数start===============================
				IfAccTimes ifAccTimes = new IfAccTimes()
						.setFieldId(log.getFieldId())
						.setSystemId(log.getSystemId()).setIfId(log.getIfId())
						.setIfName(log.getIfName())
						.setStatDate(log.getInEsbDate());
				// 记录接口访问次数end===============================

				// 批量保存信息，start===============================
				redisBatchService.batchPush(ifAlrReqTimes, ifAccTimes,
						ifAvgResTimes, pfThroughput, log,
						traceLogService.getLog());
				// 批量保存信息，end===============================

				// 记录接口告警 start======================================
				if (!alarmList.isEmpty()) {
					ifAlarmService.pushToRedis(alarmList, log);
				}
				// 记录接口告警 end======================================
			} catch (Exception e) {

			} finally {
				// 到此，已经完成所有操作，将出ESB时间加入并发数总响应时间统计队列中
				ConcurrencyNumberServiceImpl.addQueue(new Date());
				TraceLogServiceImpl.clear();
			}
		}
	}

	/**
	 * 获取邮件接收人
	 * 
	 * @param systemCode
	 *            ：发布方系统编码
	 * @param ifCode
	 *            ：接口编码
	 * @param ifVersion
	 *            ：接口版本
	 * @param callSystemCode
	 *            ：调用方系统编码
	 * @return
	 */
	private String getEmailReceiver(Token token) {
		if (token == null) {
			return "";
		}
		// 获取邮件接收者（默认为令牌申请用户
		return token.getApplyUserCode();

	}

	/**
	 * 处理代理 请求
	 *
	 * @param request
	 *            ：请求对象
	 * @param content
	 *            ：请求报文
	 * @param response
	 *            ：响应对象
	 * @param system
	 *            ：系统
	 * @param log
	 *            ：日志
	 * @param environment
	 *            ：环境
	 * @return
	 * @throws IOException
	 * @throws ServletException
	 * @throws URISyntaxException
	 */
	private int doProxy(HttpServletRequest request, byte[] bytes,
			HttpServletResponse response, FieldSystem system, Http http,
			AccLog log, HttpServlet servlet, Environment environment)
			throws IOException, ServletException, URISyntaxException {
		// 处理响应
		int statusCode = 0;
		// 生成请求对象
		String method = request.getMethod();
		// 重定向目录
		String targetUri = http.getPriUrl();
		String proxyRequestUri = rewriteUrlFromRequest(http, request,
				targetUri, system.isSendUrlFragment());
		HttpRequest proxyRequest;
		if (request.getHeader(HttpHeaders.CONTENT_LENGTH) != null
				|| request.getHeader(HttpHeaders.TRANSFER_ENCODING) != null) {
			HttpEntityEnclosingRequest eProxyRequest = new BasicHttpEntityEnclosingRequest(
					method, proxyRequestUri);
			// 设置请求超时
			if (http.getOvertimeTimes() > 0) {
				HttpConnectionParams.setConnectionTimeout(
						eProxyRequest.getParams(), http.getOvertimeTimes());
				// HttpConnectionParams.setSoTimeout(eProxyRequest.getParams(),
				// http.getOvertimeTimes());
			}
			// 添加输入流
			eProxyRequest.setEntity(new InputStreamEntity(
					new ByteArrayInputStream(bytes), bytes.length));

			// eProxyRequest.setEntity(new InputStreamEntity(
			// servletRequest.getInputStream(),servletRequest.getContentLength()));
			proxyRequest = eProxyRequest;
		} else {
			proxyRequest = new BasicHttpRequest(method, proxyRequestUri);
			// 设置请求超时
			if (http.getOvertimeTimes() > 0) {
				HttpConnectionParams.setConnectionTimeout(
						proxyRequest.getParams(), http.getOvertimeTimes());
				// HttpConnectionParams.setSoTimeout(proxyRequest.getParams(),
				// http.getOvertimeTimes());
			}
		}
		// 将servlet的请求头复制到代理请求头中去
		copyRequestHeaders(request, proxyRequest, new URI(targetUri));
		//
		setXForwardedForHeader(request, proxyRequest, system.isForwardIP());

		// 请求报文长段
		long contentLength = 0;
		// 请求结果
		String result = ReqResultType.FAILURE.ValueCode;
		// 请求结果描述
		StringBuilder reqResultDesc = new StringBuilder();
		// 跟踪日志信息
		StringBuilder traceLogMsg = new StringBuilder();
		// 设置平台处理结束时间
		Date platformEndDate = null;
		try {
			// 开始处理请求
			HttpClient proxyClient = HttpClients.createDefault();
			URI targetUriObj = new URI(targetUri);
			Date platformStartDate = new Date();
			// 转发请求开始时间
			log.setPlatReqDate(platformStartDate);
			HttpHost host = URIUtils.extractHost(targetUriObj);
			if (TraceLogServiceImpl.isTrace()) {
				// 记录跟踪日志
				TraceLogServiceImpl
						.addTraceLog(Constants.MSG_BEGIN_REQ_FORWARD);
			}
			// 转发失败，可尝试三次
			HttpResponse proxyResponse = execute(proxyClient, host,
					proxyRequest, system, http, environment);

			// 处理响应
			statusCode = proxyResponse.getStatusLine().getStatusCode();

			// 设置源响应对象状态
			response.setStatus(statusCode, proxyResponse.getStatusLine()
					.getReasonPhrase());
			// 拷贝代理响应对象头到源响应对象
			copyResponseHeaders(proxyResponse, response);

			// 读取响应报文
			contentLength = copyResponseEntity(proxyResponse, response,
					servlet, log);
			// 设置平台处理结束时间
			platformEndDate = new Date();

			// 设置请求结果描述
			reqResultDesc
					.append(proxyResponse.getStatusLine().getReasonPhrase())
					.append(Constants.FLAG_COLON).append(statusCode);
			// 记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				traceLogMsg
						.append(Constants.MSG_REQ_FORWARD_RESULT)
						.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
						.append(Constants.STATUS_CODE)
						.append(Constants.FLAG_EQUAL)
						.append(statusCode + "")
						.append(Constants.FLAG_COMMA_SYMBOL)
						.append(Constants.REASON_PHRASE)
						.append(Constants.FLAG_EQUAL)
						.append(proxyResponse.getStatusLine().getReasonPhrase())
						.append(Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			if (doResponseRedirectOrNotModifiedLogic(request, response,
					proxyResponse, statusCode, targetUri)) {
				EntityUtils.consume(proxyResponse.getEntity());
				return statusCode;
			}

			// 设置请求结果为成功
			result = ReqResultType.SUCCEED.ValueCode;
			// 记录跟踪日志，请求结果
			if (TraceLogServiceImpl.isTrace()) {
				traceLogMsg.append(Constants.MSG_REQ_SUCCESS);
			}
		} catch (Exception e) {
			// 设置请求结果为失败
			result = ReqResultType.FAILURE.ValueCode;
			// 记录跟踪日志，请求转发失败
			if (TraceLogServiceImpl.isTrace()) {
				traceLogMsg.append(Constants.MSG_REQ_FAILURE);
			}
			// 退出请求
			if (proxyRequest instanceof AbortableHttpRequest) {
				// 记录跟踪日志，请求退出
				if (TraceLogServiceImpl.isTrace()) {
					traceLogMsg.append(Constants.FLAG_DOT_SYMBOL)
							.append(Constants.MSG_DETIAL_INFO)
							.append(Constants.FLAG_COLON)
							.append(Constants.MSG_REQ_QUIT);
				}
				AbortableHttpRequest abortableHttpRequest = (AbortableHttpRequest) proxyRequest;
				abortableHttpRequest.abort();
			}
			// 记录跟踪日志,异常信息
			if (TraceLogServiceImpl.isTrace()) {
				traceLogMsg.append(Constants.FLAG_LEFT_SQUARE_BRACKET)
						.append(e.getMessage())
						.append(Constants.FLAG_RIGHT_SQUARE_BRACKET);
			}
			if (e instanceof RuntimeException)
				throw (RuntimeException) e;
			if (e instanceof ServletException)
				throw (ServletException) e;
			if (e instanceof IOException)
				throw (IOException) e;
			throw new RuntimeException(e);
		} finally {
			// 设置平台处理结束时间
			if (platformEndDate == null) {
				platformEndDate = new Date();
			}
			log.setPlatResDate(platformEndDate);
			// 设置请求结果
			log.setReqResult(result);
			// 设置吞吐量
			log.setThroughputQty((float) (contentLength) / 1024.0f);
			// 记录跟踪日志
			if (TraceLogServiceImpl.isTrace()) {
				TraceLogServiceImpl.addTraceLog(traceLogMsg.toString());
			}
		}
		return statusCode;
	}

	/**
	 * 执行转发
	 * 
	 * @param client
	 *            ：客户端
	 * @param host
	 *            ：HttpHost
	 * @param request
	 *            ：请求对象
	 * @param http
	 *            ：接口
	 * @param system
	 *            ：系统
	 * @param environment
	 *            ：环境
	 * @return
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	private HttpResponse execute(HttpClient client, HttpHost host,
			HttpRequest request, FieldSystem system, Http http,
			Environment environment) throws ClientProtocolException,
			IOException {
		// 代理响应
		HttpResponse proxyResponse = null;
		// 最大转发次数
		int max = Constants.REQ_FORWARD_TRY_TIMES;
		// 测试环境不进行存储转发
		if (Environment.TEST == environment) {
			return client.execute(host, request);
		}
		// 转发次数
		int times = 0;
		// 响应码
		int statusCode = -1;
		// 抛出异常标识
		boolean throwFlag = false;
		while (times <= max) {
			// 请求次数大于1，证明尝试多次数请求，记录尝试请求信息
			if (times > 0) {
				// 统计请求转发信息
				StoreForward reqForward = StoreForwardServiceImpl.get();
				if (reqForward.getForwardDate() == null) {
					Date date = new Date();
					reqForward.setForwardDate(date);
					reqForward.setCreateDate(date);
					reqForward.setLastUpDate(date);
				}
				reqForward.setFieldId(system.getFieldId());
				reqForward.setSystemId(system.getId());
				reqForward.setIfId(http.getId());
				reqForward.setIfName(http.getName());
				// 增加重复次数
				reqForward.incrTimes();
				// 设置状态为进行中
				reqForward.setStatus(StoreForwardStatus.PROGRESS.ValueCode);
				// 保存存储转发信息
				storeForwardService.pushToRedis();
			}
			try {
				if (http.getOvertimeTimes() > 0) {
					HttpConnectionParams.setConnectionTimeout(
							request.getParams(), http.getOvertimeTimes());
				}
				proxyResponse = client.execute(host, request);
				statusCode = proxyResponse.getStatusLine().getStatusCode();
				// 请求成功，退出循环
				if (statusCode == 200) {
					break;
				}
			} catch (Exception e) {
				// 已达转发上限，抛出异常
				if (times == max) {
					throwFlag = true;
					throw e;
				}
			} finally {
				// 请求次数大于1，证明尝试多次数请求，记录尝试请求信息
				if (times > 0) {
					// 统计请求转发信息
					StoreForward reqForward = StoreForwardServiceImpl.get();
					// 设置状态为失败
					reqForward.setStatus(StoreForwardStatus.FAILURE.ValueCode);
					// 保存存储转发信息
					storeForwardService.pushToRedis();
				}
				// 抛出异常，清理数据
				if (throwFlag) {
					// 清除当前线程存储转发数据
					StoreForwardServiceImpl.clear();
				}
			}
			times++;
		}
		// 请求次数大于1，证明尝试多次数请求，记录尝试请求信息
		if (times > 0) {
			// 统计请求转发信息
			StoreForward reqForward = StoreForwardServiceImpl.get();
			if (statusCode == 200) {
				// 设置状态为成功
				reqForward.setStatus(StoreForwardStatus.SUCCESS.ValueCode);
			} else {
				// 设置状态为失败
				reqForward.setStatus(StoreForwardStatus.FAILURE.ValueCode);
			}
			// 保存存储转发信息
			storeForwardService.pushToRedis();
		}
		// 清除当前线程存储转发数据
		StoreForwardServiceImpl.clear();
		return proxyResponse;
	}

	/**
	 * 请求量控制
	 * 
	 * @param ifReqQuantity
	 *            ：接口请求量控制
	 * @param ifAlrReqTimes
	 *            ：接口已请求次数
	 * @param reqTime
	 *            ：请求时间
	 * @return
	 * @throws IfAlarmException
	 */
	private IfAlarm alarm(IfReqQuantity ifReqQuantity,
			IfAlrReqTimes ifAlrReqTimes, Date reqTime) throws IfAlarmException {
		if (TraceLogServiceImpl.isTrace()) {
			// 记录跟踪日志
			TraceLogServiceImpl.addTraceLog(Constants.MSG_VERIFY_REQ_QTY);
		}
		// 检查是否有告警
		return ifReqQuantityService
				.alarm(ifReqQuantity, ifAlrReqTimes, reqTime);
	}

	/**
	 * 读取请求内容
	 * 
	 * @param request
	 *            ：请求对象
	 * @return
	 */
	private byte[] readContent(HttpServletRequest request) {
		try {
			InputStream input = request.getInputStream();
			ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
			byte[] buffer = new byte[1024];
			int len = -1;
			while ((len = input.read(buffer)) != -1) {
				outSteam.write(buffer, 0, len);
			}
			byte[] b = outSteam.toByteArray();

			input.close();
			outSteam.close();
			return b;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 创建日志对象
	 * 
	 * @return
	 */
	private static AccLog createLog() {
		AccLog log = new AccLog();
		// 默认为可用
		log.setIsEnable(EnableType.ENABLE.ValueCode);
		log.setCreatedDate(new Date());
		return log;
	}

	protected boolean doResponseRedirectOrNotModifiedLogic(
			HttpServletRequest servletRequest,
			HttpServletResponse servletResponse, HttpResponse proxyResponse,
			int statusCode, String targetUri) throws ServletException,
			IOException {
		if (statusCode >= HttpServletResponse.SC_MULTIPLE_CHOICES /* 300 */
				&& statusCode < HttpServletResponse.SC_NOT_MODIFIED /* 304 */) {
			Header locationHeader = proxyResponse
					.getLastHeader(HttpHeaders.LOCATION);
			if (locationHeader == null) {
				String msg = "Received status code: " + statusCode + " but no "
						+ HttpHeaders.LOCATION
						+ " header was found in the response";
				if (TraceLogServiceImpl.isTrace()) {
					// 记录跟踪日志
					TraceLogServiceImpl.addTraceLog(msg);
				}
				throw new ServletException(msg);
			}
			// 修改重定向到代理的servlet
			String locStr = rewriteUrlFromResponse(servletRequest,
					locationHeader.getValue(), targetUri);

			servletResponse.sendRedirect(locStr);
			return true;
		}
		if (statusCode == HttpServletResponse.SC_NOT_MODIFIED) {
			servletResponse.setIntHeader(HttpHeaders.CONTENT_LENGTH, 0);
			servletResponse.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
			return true;
		}
		return false;
	}

	protected void closeQuietly(Closeable closeable, HttpServlet httpServlet) {
		try {
			closeable.close();
		} catch (IOException e) {
			httpServlet.log(e.getMessage(), e);
		}
	}

	/**
	 * 将servlet的请求头复制到代理请求头中去
	 *
	 * @param servletRequest
	 * @param proxyRequest
	 * @param targetUriObj
	 */
	protected void copyRequestHeaders(HttpServletRequest servletRequest,
			HttpRequest proxyRequest, URI targetUriObj) {
		// 获得http头部所有名称的枚举
		Enumeration enumerationOfHeaderNames = servletRequest.getHeaderNames();
		while (enumerationOfHeaderNames.hasMoreElements()) {
			String headerName = (String) enumerationOfHeaderNames.nextElement();
			if (headerName.equalsIgnoreCase(HttpHeaders.CONTENT_LENGTH))
				continue;
			if (hopByHopHeaders.containsHeader(headerName))
				continue;

			Enumeration headers = servletRequest.getHeaders(headerName);
			while (headers.hasMoreElements()) {
				String headerValue = (String) headers.nextElement();

				if (headerName.equalsIgnoreCase(HttpHeaders.HOST)) {
					HttpHost host = URIUtils.extractHost(targetUriObj);
					headerValue = host.getHostName();
					if (host.getPort() != -1)
						headerValue += ":" + host.getPort();
				}
				proxyRequest.addHeader(headerName, headerValue);
			}
		}
	}

	private void setXForwardedForHeader(HttpServletRequest servletRequest,
			HttpRequest proxyRequest, boolean doForwardIP) {
		String headerName = "X-Forwarded-For";
		if (doForwardIP) {
			String newHeader = servletRequest.getRemoteAddr();
			String existingHeader = servletRequest.getHeader(headerName);
			if (existingHeader != null) {
				newHeader = existingHeader + ", " + newHeader;
			}
			proxyRequest.setHeader(headerName, newHeader);
		}
	}

	/**
	 * 拷贝代理响应对象头到源响应对象
	 *
	 * @param proxyResponse
	 * @param servletResponse
	 */
	protected void copyResponseHeaders(HttpResponse proxyResponse,
			HttpServletResponse servletResponse) {
		for (Header header : proxyResponse.getAllHeaders()) {
			if (hopByHopHeaders.containsHeader(header.getName())) {
				continue;
			}
			servletResponse.addHeader(header.getName(), header.getValue());
		}
	}

	/**
	 * 拷贝代理响应对象数据到源响应对象
	 *
	 * @param proxyResponse
	 * @param servletResponse
	 * @param log
	 * @throws IOException
	 */
	protected long copyResponseEntity(HttpResponse proxyResponse,
			HttpServletResponse servletResponse, HttpServlet httpServlet,
			AccLog log) throws IOException {
		long length = 0;
		HttpEntity entity = proxyResponse.getEntity();
		if (entity != null) {
			OutputStream servletOutputStream = servletResponse
					.getOutputStream();
			try {
				length = entity.getContentLength();
				// 数据量较小，一次性读取：START======================
				if (length >= 0) {
					entity.writeTo(servletOutputStream);
					return length;
				}
				// 数据量较小，一次性读取：END======================

				// 数据量较大，分匹读取：START======================
				int readeSize = Constants.EACH_READE_FEFAULT_SIZE_BIG;
				byte[] bytes = new byte[readeSize];
				int size = 0;
				InputStream inputStream = entity.getContent();
				while ((size = inputStream.read(bytes)) > 0) {
					servletOutputStream.write(bytes, 0, size);
					length += size;
				}
				// 数据量较大，分匹读取：END======================
			} finally {
				log.setThroughputQty((float) (length) / 1024.0f);
				closeQuietly(servletOutputStream, httpServlet);
			}
		}
		return length;
	}

	protected String rewriteUrlFromRequest(Http http,
			HttpServletRequest servletRequest, String targetUri,
			boolean doSendUrlFragment) {
		// 对于WS接口类型，按规范没有URL参数
		if (IfType.WS.ValueCode.equals(http.getType())) {
			return targetUri;
		}
		StringBuilder uri = new StringBuilder(500);
		String queryString = "";
		if (servletRequest.getPathInfo() != null) {
			String path = servletRequest.getPathInfo();
			path = path.substring(1);
			path = path.substring(path.indexOf("/"));
			// remove system code
			path = path.substring(path.indexOf("/") + 1);
			// remove interface version
			path = path.substring(path.indexOf("/") + 1);
			// remove interface code
			path = path.substring(path.indexOf("/") + 1);
			CharSequence encode = encodeUriQuery(path);
			if (encode != null) {
				queryString = encode.toString();
			}
		}
		// 没有查询参数，返回目标URL
		if (StringUtils.isBlank(queryString)) {
			return targetUri;
		}
		uri.append(targetUri);

		uri.append("?");
		uri.append(queryString);
		return uri.toString();
	}

	protected String rewriteUrlFromResponse(HttpServletRequest servletRequest,
			String theUrl, String targetUri) {
		if (theUrl.startsWith(targetUri)) {
			String curUrl = servletRequest.getRequestURL().toString();// no
																		// query
			String pathInfo = servletRequest.getPathInfo();
			if (pathInfo != null) {
				assert curUrl.endsWith(pathInfo);
				curUrl = curUrl.substring(0,
						curUrl.length() - pathInfo.length());// take pathInfo
																// off
			}
			theUrl = curUrl + theUrl.substring(targetUri.length());
		}
		return theUrl;
	}

	/**
	 * 对分段式的uri进行编码
	 *
	 * @param in
	 * @return
	 */
	protected static CharSequence encodeUriQuery(CharSequence in) {
		StringBuilder outBuf = null;
		Formatter formatter = null;
		for (int i = 0; i < in.length(); i++) {
			char c = in.charAt(i);
			boolean escape = true;
			if (c < 128) {
				if (asciiQueryChars.get((int) c)) {
					escape = false;
				}
			} else if (!Character.isISOControl(c) && !Character.isSpaceChar(c)) {// not-ascii
				escape = false;
			}
			if (!escape) {
				if (outBuf != null)
					outBuf.append(c);
			} else {
				// escape
				if (outBuf == null) {
					outBuf = new StringBuilder(in.length() + 5 * 3);
					outBuf.append(in, 0, i);
					formatter = new Formatter(outBuf);
				}
				// leading %, 0 padded, width 2, capital hex
				formatter.format("%%%02X", (int) c);// TODO
			}
		}
		return outBuf != null ? outBuf : in;
	}

	public AuthInvocation getAuthInvocation() {
		return authInvocation;
	}

	public void setAuthInvocation(AuthInvocation authInvocation) {
		this.authInvocation = authInvocation;
	}

	public FieldSystemService getFieldSystemService() {
		return fieldSystemService;
	}

	public void setFieldSystemService(FieldSystemService fieldSystemService) {
		this.fieldSystemService = fieldSystemService;
	}

	public HttpService getHttpService() {
		return httpService;
	}

	public void setHttpService(HttpService httpService) {
		this.httpService = httpService;
	}

	public IfAlarmService getIfAlarmService() {
		return ifAlarmService;
	}

	public void setIfAlarmService(IfAlarmService ifAlarmService) {
		this.ifAlarmService = ifAlarmService;
	}

	public IfReqQuantityService getIfReqQuantityService() {
		return ifReqQuantityService;
	}

	public void setIfReqQuantityService(
			IfReqQuantityService ifReqQuantityService) {
		this.ifReqQuantityService = ifReqQuantityService;
	}

	public IfAlrReqTimesService getIfAlrReqTimesService() {
		return ifAlrReqTimesService;
	}

	public void setIfAlrReqTimesService(
			IfAlrReqTimesService ifAlrReqTimesService) {
		this.ifAlrReqTimesService = ifAlrReqTimesService;
	}

	public TraceLogService getTraceLogService() {
		return traceLogService;
	}

	public void setTraceLogService(TraceLogService traceLogService) {
		this.traceLogService = traceLogService;
	}

	public StoreForwardService getStoreForwardService() {
		return storeForwardService;
	}

	public void setStoreForwardService(StoreForwardService storeForwardService) {
		this.storeForwardService = storeForwardService;
	}

	public ConcurrencyNumberService getConcurrencyNumberService() {
		return concurrencyNumberService;
	}

	public void setConcurrencyNumberService(
			ConcurrencyNumberService concurrencyNumberService) {
		this.concurrencyNumberService = concurrencyNumberService;
	}

	public RedisBatchService getRedisBatchService() {
		return redisBatchService;
	}

	public void setRedisBatchService(RedisBatchService redisBatchService) {
		this.redisBatchService = redisBatchService;
	}

}
